#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<termios.h>

#include<sys/time.h>
#include<signal.h>
 
struct itimerval timer = {0};
int timer_count = 0;

int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)
{
    struct termios newtio,oldtio;
    if (tcgetattr(fd,&oldtio)  !=  0)
    {
        printf("tcgetattr() failed!!!\n");
        return -1;
    }
    
    bzero( &newtio, sizeof( newtio ) );
    newtio.c_cflag  |=  CLOCAL | CREAD; //CLOCAL:忽略modem控制线  CREAD：打开接受者
    newtio.c_cflag &= ~CSIZE; //字符长度掩码。取值为：CS5，CS6，CS7或CS8

    switch(nBits )
    {
    case 7:
        newtio.c_cflag |= CS7;
        break;
    case 8:
        newtio.c_cflag |= CS8;
        break;
    }

    switch(nEvent)
    {
    case 'O':
        newtio.c_cflag |= PARENB; //允许输出产生奇偶信息以及输入到奇偶校验
        newtio.c_cflag |= PARODD;  //输入和输出是奇及校验
        newtio.c_iflag |= (INPCK | ISTRIP); // INPACK:启用输入奇偶检测；ISTRIP：去掉第八位
        break;
    case 'E':
        newtio.c_iflag |= (INPCK | ISTRIP);
        newtio.c_cflag |= PARENB;
        newtio.c_cflag &= ~PARODD;
        break;
    case 'N': 
        newtio.c_cflag &= ~PARENB;
        break;
    }

    switch(nSpeed )
    {
    case 2400:
        cfsetispeed(&newtio, B2400);
        cfsetospeed(&newtio, B2400);
        break;
    case 4800:
        cfsetispeed(&newtio, B4800);
        cfsetospeed(&newtio, B4800);
        break;
    case 9600:
        cfsetispeed(&newtio, B9600);
        cfsetospeed(&newtio, B9600);
        break;
    case 115200:
        cfsetispeed(&newtio, B115200);
        cfsetospeed(&newtio, B115200);
        break;
    case 460800:
        cfsetispeed(&newtio, B460800);
        cfsetospeed(&newtio, B460800);
        break;
    default:
        cfsetispeed(&newtio, B9600);
        cfsetospeed(&newtio, B9600);
        break;
    }

    if (nStop == 1)
        newtio.c_cflag &=  ~CSTOPB; //CSTOPB:设置两个停止位，而不是一个
    else if (nStop == 2)
        newtio.c_cflag |=  CSTOPB;

    newtio.c_cc[VTIME]  = 0; //VTIME:非cannoical模式读时的延时，以十分之一秒位单位
    newtio.c_cc[VMIN] = 0; //VMIN:非canonical模式读到最小字符数
    tcflush(fd,TCIFLUSH); // 改变在所有写入 fd 引用的对象的输出都被传输后生效，所有已接受但未读入的输入都在改变发生前丢弃。

    if((tcsetattr(fd,TCSANOW,&newtio))  != 0) //TCSANOW:改变立即发生
    {
        printf("com set error!!!\n");
        return -1;
    }
    
    printf("set done!\n");
    return 0;
}
 
void sigroutine(int signo){
   switch (signo)
   {
   case SIGALRM:
        timer_count++;
        printf("tm:%dms\n", timer_count);
        signal(SIGALRM, sigroutine);
        break;
   }
   return;
}

int main(int argc, char **argv)
{
    int fd = -1;
    int nset,nread,ret;
    char buf[100]={"111111"};
    char buf1[100];
    int i = 0;
    char *device;
    int nSpeed, nBits, nEvent,nStop;
    
    fd_set  recv_fds;  /* 定义接收fds  一个存放文件描述符(file descriptor)，即文件句柄的聚合，实际上是一long类型的数组 */
    int     maxfd   = 0;    /* 定义最大句柄 */
    int     fd_result;
    struct  timeval tv;       /* 超时时间 */

    tv.tv_sec   = 10;       //设定超时时间 
    tv.tv_usec  = 0;          //10000us = 10ms
    
    device = argv[1];
    #if 0
    nSpeed = atoi(argv[2]);
    nBits  = atoi(argv[3]);
    nEvent = atoi(argv[4]);
    nStop  = atoi(argv[5]);
    #endif

    signal(SIGALRM, sigroutine);
    timer.it_value.tv_sec = 0;
    timer.it_value.tv_usec = 1000;  /* 定时1ms */
    timer.it_interval.tv_sec = 1;
    timer.it_interval.tv_usec = 0;
    setitimer(ITIMER_REAL, &timer, NULL);
    
    fd = open(device, O_RDWR);
    if (fd == -1)
    {
        printf("Failed to open device [%s]!\n",device);
        return -1;
    }   

    printf("open %s success!!\n",device);

    nset = set_opt(fd, 115200, 8, 'N', 1);
    if (nset == -1)
        return -1;
    
    printf("SET  %s success!!\n",device);
    printf("Enter the loop!!\n");

    if(fd > maxfd)
    {
        maxfd = fd;
    }

    for(;;)
    {   
        /* 注意每次都要重新设置 */
        FD_ZERO(&recv_fds);
        FD_SET(fd,&recv_fds);           /* 分别把句柄加入读监视集合里去   */

        // write(fd, buf, 6); 
        // printf("Write success\r\n");

        fd_result = select(maxfd + 1, &recv_fds, NULL, NULL, &tv);  /* 注意是最大值加1                   */
        if(fd_result < 0)
        {
            printf("select err");      /* select函数出错                 */
            usleep(10000);
            continue;
        }
        else if(fd_result == 0)
        {
//            printf("select time out \n"); /* 在设定的tv时间内，socket的状态没有发生变化 */
            usleep(10000);
            continue;
        }
        else                                                        /* 开始读数据 */
        {
		    printf("Receive data.........\n");
            if(FD_ISSET(fd, &recv_fds))                      /* 先判断一下是哪个句柄可读 */
            {
                memset(buf1, 0, sizeof(buf1));
				nread = read(fd, buf1, 48);
				if(nread > 0)
				{
					//printf("*********************************receive data***************************\n");
					for (i =0; i <48; i++)
						printf("%#x ",buf1[i]);
				}
				printf("\nrecive data number=%#x\n",nread);
				printf("+++++++++++++++++++++++++++++++++++++++++++++\n");
            }
        }
    }
    
    close(fd);

    return 0;
}



